#pragma once

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <mutex>

using namespace std;

#ifdef ENABLE_USE_LOGCPLUS 
#include "logcplus/logcplus_writer_file.h"
using namespace logcplus;
#endif 

namespace tnet
{
    class LogUtil
    {
    public:
        enum Level{TRACE = 0,DEBUG,INFO,WARN,ERROR,FATAL};

        LogUtil();
        ~LogUtil();

        static LogUtil& rootLog();

        inline void setLevel(LogUtil::Level level) { m_level = level;};
        inline void setType(uint8_t type) { m_logtype = type;};
        inline void setDir(const string& dir) { m_dir = dir;};

        int  openlog(const string& logname);
        void closelog();
        
        void trace(const char* file, const char* function, int line, const char* fmt, ...);
        void debug(const char* file, const char* function, int line, const char* fmt, ...);
        void info( const char* file, const char* function, int line, const char* fmt, ...);
        void warn( const char* file, const char* function, int line, const char* fmt, ...);
        void error(const char* file, const char* function, int line, const char* fmt, ...);
        void fatal(const char* file, const char* function, int line, const char* fmt, ...);
        
    private:
        void redirect(const char* fileName);
        int  makepath();
        int  openlog();
        void logger( const char* level, const char* file, const char* function, int line,  const char* msg);
        int  lock();
        int  unlock();
    private:
        FILE* m_fd;
        string m_date;
        string m_dir;
        string m_logname;
        string m_logfile;
        uint16_t  m_level;
        uint8_t m_logtype;
        std::mutex m_lock;
    };

#ifndef ENABLE_USE_LOGCPLUS    
    #define LOGMCRO __FILE__, __FUNCTION__, __LINE__
    #define LOG_HANDLE 	LogUtil::rootLog()
    #define LOG_INIT(logname)              LOG_HANDLE.openlog(logname)
    #define LOG_SETLEVEL(LOGLEVEL)         LOG_HANDLE.setLevel((LogUtil::Level)LOGLEVEL)
    #define LOG_TRACE(fmt, args...)        LOG_HANDLE.trace(LOGMCRO, fmt, ##args)
    #define LOG_DEBUG(fmt, args...)        LOG_HANDLE.debug(LOGMCRO, fmt, ##args)
    #define LOG_INFO( fmt, args...)        LOG_HANDLE.info( LOGMCRO, fmt, ##args)
    #define LOG_WARN( fmt, args...)        LOG_HANDLE.warn( LOGMCRO, fmt, ##args)
    #define LOG_ERROR(fmt, args...)        LOG_HANDLE.error(LOGMCRO, fmt, ##args)
    #define LOG_FATAL(fmt, args...)        LOG_HANDLE.fatal(LOGMCRO, fmt, ##args)  
    #define LOG_UNINIT()                   LOG_HANDLE.closelog()
#endif
}